package io.gitee.yaoshanli.engine.db;

import com.alibaba.druid.pool.DruidDataSource;
import io.gitee.yaoshanli.engine.db.dialect.*;
import org.apache.commons.lang3.StringUtils;
import io.gitee.yaoshanli.engine.utils.ConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.*;
import java.util.Collection;
import java.util.Properties;

/**
 * @author 姚善利
 * @classname org.jwflow.engine.db.JdbcHelper
 * @description  数据库连接处理类
 * @date 2022/9/21 8:35
 */
public class JdbcHelper {
    private static final Logger log = LoggerFactory.getLogger(JdbcHelper.class);
    private static DataSource dataSource = null;


    private static Properties databaseTypeMappings = getDefaultDatabaseTypeMappings();

    private static Properties getDefaultDatabaseTypeMappings() {
        Properties databaseTypeMappings = new Properties();
        databaseTypeMappings.setProperty("H2","h2");
        databaseTypeMappings.setProperty("MySQL","mysql");
        databaseTypeMappings.setProperty("Oracle","oracle");
        databaseTypeMappings.setProperty("PostgreSQL","postgres");
        databaseTypeMappings.setProperty("Microsoft SQL Server","mssql");
        databaseTypeMappings.setProperty("DB2","db2");
        return databaseTypeMappings;
    }
    /**
     * 在没有任何dataSource注入的情况下，默认使用dbcp数据源
     */
    public static void initialize() {
        String driver = ConfigUtils.getProperty("jdbc.driver");
        String url = ConfigUtils.getProperty("jdbc.url");
        String username = ConfigUtils.getProperty("jdbc.username");
        String password = ConfigUtils.getProperty("jdbc.password");
        int maxActive = ConfigUtils.getNumerProperty("jdbc.max.active");
        int maxIdle = ConfigUtils.getNumerProperty("jdbc.max.idle");
        //初始化DBCP数据源
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        if(maxActive != 0) {
            ds.setMaxActive(maxActive);
        }
        if(maxIdle != 0) {
            ds.setMaxIdle(maxIdle);
        }
        dataSource = ds;
    }

    /**
     * 返回数据源dataSource
     * @return
     */
    public static DataSource getDataSource() {
        if(dataSource == null) {
            synchronized (JdbcHelper.class) {
                if(dataSource == null) {
                    initialize();
                }
            }
        }
        return dataSource;
    }

    /**
     * 返回数据库连接对象
     * @return
     * @throws SQLException
     */
    public static Connection getConnection(DataSource ds) throws SQLException {
        //通过ThreadLocale中获取Connection，如果为空，则通过dataSource返回新的连接对象
        Connection conn = null;
        if(conn != null) return conn;
        if(ds != null) return ds.getConnection();
        return getDataSource().getConnection();
    }

    /**
     * conn不为空时，关闭conn
     * @param conn
     * @throws SQLException
     */
    public static void close(Connection conn) throws SQLException {
        if (conn != null) {
            conn.close();
        }
    }

    /**
     * rs不为空时，关闭rs
     * @param rs
     * @throws SQLException
     */
    public static void close(ResultSet rs) throws SQLException {
        if (rs != null) {
            rs.close();
        }
    }

    /**
     * stmt不为空时，关闭stmt
     * @param stmt
     * @throws SQLException
     */
    public static void close(Statement stmt) throws SQLException {
        if (stmt != null) {
            stmt.close();
        }
    }


    /**
     * 根据连接对象获取数据库类型
     * @param conn 数据库连接
     * @return 类型
     * @throws Exception
     */
    public static String getDatabaseType(Connection conn) throws Exception {
        DatabaseMetaData databaseMetaData = conn.getMetaData();
        String databaseProductName = databaseMetaData.getDatabaseProductName();
        return databaseTypeMappings.getProperty(databaseProductName);
    }

    /**
     * 根据连接对象获取数据库方言
     * @param conn 数据库连接
     * @return Dialect 方言
     * @throws Exception
     */
    public static Dialect getDialect(Connection conn) throws Exception {
        DatabaseMetaData databaseMetaData = conn.getMetaData();
        String databaseProductName = databaseMetaData.getDatabaseProductName();
        String dbType = databaseTypeMappings.getProperty(databaseProductName);
        if(StringUtils.isEmpty(dbType)) return null;
        if(dbType.equalsIgnoreCase("mysql")) return new MySqlDialect();
        else if(dbType.equalsIgnoreCase("oracle")) return new OracleDialect();
        else if(dbType.equalsIgnoreCase("postgres")) return new PostgresqlDialect();
        else if(dbType.equalsIgnoreCase("mssql")) return new SQLServerDialect();
        else if(dbType.equalsIgnoreCase("db2")) return new Db2Dialect();
        else if(dbType.equalsIgnoreCase("h2")) return new H2Dialect();
        else return null;
    }

    /**
     * 根据返回的对象集合判断是否为单条记录，并返回
     * 如果返回无记录，或者超过1条记录，则抛出异常
     * @param results
     * @return
     */
    public static <T> T requiredSingleResult(Collection<T> results) {
        int size = (results != null ? results.size() : 0);
        if (size == 0) {
            return null;
        }
        return results.iterator().next();
    }
}
